package com.chookss.tools.okgoconfig;

import android.content.Context;

import com.chookss.MyApp;
import com.chookss.base.AppStatus;
import com.chookss.base.AppStatusManager;
import com.chookss.base.StaticClass;
import com.chookss.base.Token;
import com.chookss.home.entity.UploadEntity;
import com.chookss.tools.MyEvent;
import com.chookss.tools.MyToast;
import com.chookss.tools.SignUtils2;
import com.chookss.tools.Utils;
import com.chookss.tools.okgoconfig.callback.JsonCallback;
import com.chookss.tools.okgoconfig.callback.JsonConvert;
import com.chookss.tools.okgoconfig.callback.ObserverCallback;
import com.chookss.tools.okgoconfig.model.LzyResponse;
import com.chookss.tools.okgoconfig.utils.Convert;
import com.chookss.view.LoadingDialog;
import com.johnrambo.ktea.common.klogutil.KLog;
import com.johnrambo.ktea.ktExtends.ShareUtils;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.cache.CacheMode;
import com.lzy.okgo.convert.StringConvert;
import com.lzy.okgo.request.base.Request;
import com.lzy.okrx2.adapter.ObservableBody;
import com.trello.rxlifecycle2.android.ActivityEvent;
import com.trello.rxlifecycle2.android.FragmentEvent;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
import com.trello.rxlifecycle2.components.support.RxFragment;

import org.greenrobot.eventbus.EventBus;

import java.io.File;
import java.lang.ref.WeakReference;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;

/**
 * okgo网络请求类工具
 */
public class MyHttpRequest {
    private final static MyHttpRequest DEFAULT = new MyHttpRequest();
    private final static int POST = 0X001;
    // 三个hour(避免太长，后台测试故意改数据不变化)
    private final static Long CACHE_TIME = 10800000L;
    private final static int GET = 0x002;

    private MyHttpRequest() {
    }

    public static <T> void getRequest(String url, Object tag, Map<String, String> map, JsonCallback<T> callback) {
        try {
            if (AppStatusManager.getInstance().getAppStatus() == AppStatus.STATUS_RECYVLE) {
                return;
            }
            if (Utils.isNull(Token.INSTANCE.getToken())) {
                Token.INSTANCE.setToken(new ShareUtils().getString(MyApp.appCtx, StaticClass.TOKEN, ""));
                Token.INSTANCE.setVersionName(new ShareUtils().getString(MyApp.appCtx, StaticClass.VERSIONNAME, ""));
            }
            OkGo.<T>get(url)
                    .tag(tag)
                    .params(map)
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> void getRequestCache(CacheMode cacheMode, String url, String cacheKey, Object tag, Map<String, String> map, JsonCallback<T> callback) {

        try {
            OkGo.<T>get(url)
                    .tag(tag)
                    .cacheKey(cacheKey)
                    .cacheTime(CACHE_TIME)
                    .cacheMode(cacheMode)
                    .params(map)
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> void postRequest(String url, Object tag, Map<String, String> map, JsonCallback<T> callback) {
        try {
            if (AppStatusManager.getInstance().getAppStatus() == AppStatus.STATUS_RECYVLE) {
                return;
            }
            if (Utils.isNull(Token.INSTANCE.getToken())) {
                Token.INSTANCE.setToken(new ShareUtils().getString(MyApp.appCtx, StaticClass.TOKEN, ""));
                Token.INSTANCE.setVersionName(new ShareUtils().getString(MyApp.appCtx, StaticClass.VERSIONNAME, ""));
            }
            OkGo.<T>post(url)
                    .tag(tag)
                    .params(map)
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> void postRequestJson(String url, Object tag, String json, JsonCallback<T> callback) {
        try {
            if (AppStatusManager.getInstance().getAppStatus() == AppStatus.STATUS_RECYVLE) {
                return;
            }
            MediaType JSON = MediaType.parse("application/json; charset=utf-8");
            RequestBody body = RequestBody.create(JSON, json);
//            String urls=url;
            String urls = url + "?" + SignUtils2.makeSignStr2(null);
            OkGo.<T>post(urls)
                    .tag(tag)
                    .upRequestBody(body)
                    .upJson(json)
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> void upLoadFiles(String url, Object tag, Map<String, String> map, String fileType, List<File> files, JsonCallback<T> callback) {
        try {
            KLog.i("=====upLoadFiles"+files.size());
            OkGo.<T>post(url)
                    .tag(tag)
                    .params(map)
                    .addFileParams(fileType, files)
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> void upLoadFile(String url, Object tag, Map<String, String> map, boolean noCut, String fileType, File file, JsonCallback<T> callback) {
        try {
            if (noCut) {
                OkGo.<T>post(url)
                        .tag(tag)
                        .params("cut", true)
                        .params("width", 300)
                        .params("height", 300)
                        .params(fileType, file)
                        .execute(callback);
            } else {
                OkGo.<T>post(url)
                        .tag(tag)
                        .params(fileType, file)
                        .execute(callback);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> void uploadPicture(String url, Object tag, String source, File file, JsonCallback<T> callback) {
        try {
//            source 数据来源(1基本信息 2新闻 3图文 4日志)
            OkGo.<T>post(url)
                    .tag(tag)
                    .params("file", file)
                    .params("source", source)
                    .retryCount(3)
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static <T> void uploadDataFileNew(String url, Object tag, File file, JsonCallback<T> callback) {
        try {
//            source 数据来源(1基本信息 2新闻 3图文 4日志)
            OkGo.<T>post(url)
                    .tag(tag)
                    .params("files", file)
                    .params("catalogCode", "4002")
                    .params("costFlag", "0")
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static <T> void uploadDocFile(String url, Object tag, UploadEntity.DataBaseBean docunmentBean, JsonCallback<T> callback) {
        try {
//            source 数据来源(1基本信息 2新闻 3图文 4日志)
            OkGo.<T>post(url)
                    .tag(tag)
                    .params("file", new File(docunmentBean.getLocalDataPath()))
                    .params("parentCode", docunmentBean.getParentCode())
                    .params("parentName", docunmentBean.getParentName())
                    .params("dataTitle", docunmentBean.getDataTitle())
                    .params("dataSize", docunmentBean.getDataSize())
                    .params("provideEmployeeCode", docunmentBean.getProvideEmployeeCode())
                    .params("provideEmployeeName", docunmentBean.getProvideEmployeeName())
                    .params("fileType", docunmentBean.getFileType())
                    .params("original", docunmentBean.getOriginal())
                    .params("shareFlag", docunmentBean.getShareFlag())
                    .params("downloadFlag", "1")
                    .params("startTime", Utils.getCurrentTime2())
                    .execute(callback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static MyHttpRequest getDefault() {
        return DEFAULT;
    }

    /**
     * get方法
     *
     * @param typeToken         泛型获取typetoken
     * @param theLifeObj        绑定生命周期
     * @param url               地址
     * @param map               参数
     * @param showLoadingDialog 是否展示加载框
     * @param callback          结果
     * @param <T>               返回泛型
     */
    public <T> void getRequest(Type typeToken, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<T> callback) {
        request(GET, typeToken, theLifeObj, url, map, showLoadingDialog, callback, CacheMode.NO_CACHE);
    }

    public <T> void getRequestHideToast(Type typeToken, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<T> callback) {
        request(GET, typeToken, theLifeObj, url, map, showLoadingDialog, callback, CacheMode.NO_CACHE, true);
    }

    /**
     * 非get即post ，后续需要其他再进行判断
     */
    private void requestCompat(int requestType, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<String> callback, CacheMode cache) {
        if (AppStatusManager.getInstance().getAppStatus() == AppStatus.STATUS_RECYVLE) {
            return;
        }
        if (Utils.isNull(Token.INSTANCE.getToken())) {
            MyApp.setAppSetting("");
        }
        Request<LzyResponse<String>, ? extends Request> request;
        if (requestType == GET) {
            request = OkGo.get(url);
        } else {
            request = OkGo.post(url);
        }
//        KLog.i(url);
//        KLog.i(map);
        //算出cachekey
        if (null != map && map.containsKey("pageIndex")) {
            String pageIndex = map.get("pageIndex");
            url = url + pageIndex;
        }
        request.cacheKey(url).cacheMode(cache).cacheTime(CACHE_TIME);
        Observable<String> observable = (Observable<String>) request.params(map)
                .converter(new StringConvert())
                .adapt(new ObservableBody<String>());
        observable = observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
        if (theLifeObj instanceof RxAppCompatActivity) {
            RxAppCompatActivity activity = (RxAppCompatActivity) theLifeObj;
            observable = observable.compose(activity.bindUntilEvent(ActivityEvent.DESTROY));
            if (showLoadingDialog) observable = observable.compose(compose(activity));
        } else if (theLifeObj instanceof RxFragment) {
            RxFragment fragment = (RxFragment) theLifeObj;
            observable = observable.compose(fragment.bindUntilEvent(FragmentEvent.DESTROY_VIEW));
            if (showLoadingDialog) observable = observable.compose(compose(fragment.getContext()));
        }
        observable
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(String t) {
                        try {
                            if (callback != null) {
                                //打印请求结果
                                KLog.json(t);
                                callback.onSuccess(t);
                            }

                        } catch (Exception e) {
                            onError(e);
                        }

                    }

                    @Override
                    public void onError(Throwable e) {
                        String message = e.getMessage();
                        if (Utils.isNull(message)) return;
                        if (callback != null)
                            callback.onError(message);

                        if (message.contains("Failed to") || message.contains("resolve host")) {
                            MyToast.show("网络不可用,请设置网络");
                        } else if (message.contains("BEGIN_OBJECT") || message.contains("IllegalStateException") || message.contains("4") || message.contains("5") || message.contains("failed")) {
                            MyToast.show("服务器异常，请稍后重试");
                        } else if (message.contains("but")) {
                            MyToast.show("数据格式不正确");
                        }
                    }

                    @Override
                    public void onComplete() {
                    }

                });
    }

    private void requestCompatHideToast(int requestType, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<String> callback, CacheMode cache) {

        Request<LzyResponse<String>, ? extends Request> request;
        if (requestType == GET) {
            request = OkGo.get(url);
        } else {
            request = OkGo.post(url);
        }
        //算出cachekey
        if (null != map && map.containsKey("pageIndex")) {
            String pageIndex = map.get("pageIndex");
            url = url + pageIndex;
        }
        request.cacheKey(url).cacheMode(cache).cacheTime(CACHE_TIME);
        Observable<String> observable = (Observable<String>) request.params(map)
                .converter(new StringConvert())
                .adapt(new ObservableBody<String>());
        observable = observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
        if (theLifeObj instanceof RxAppCompatActivity) {
            RxAppCompatActivity activity = (RxAppCompatActivity) theLifeObj;
            observable = observable.compose(activity.bindUntilEvent(ActivityEvent.DESTROY));
            if (showLoadingDialog) observable = observable.compose(compose(activity));
        } else if (theLifeObj instanceof RxFragment) {
            RxFragment fragment = (RxFragment) theLifeObj;
            observable = observable.compose(fragment.bindUntilEvent(FragmentEvent.DESTROY_VIEW));
            if (showLoadingDialog) observable = observable.compose(compose(fragment.getContext()));
        }
        observable
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(String t) {
                        try {
                            if (callback != null)
                                callback.onSuccess(t);
                        } catch (Exception e) {
                            onError(e);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        String message = e.getMessage();
                        if (callback != null)
                            callback.onError(message);
                    }

                    @Override
                    public void onComplete() {
                    }

                });
    }


    /**
     * 非get即post ，后续需要其他再进行判断
     */
    private <T> void request(int requestType, Type typeToken, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<T> callback, CacheMode cache) {
        if (AppStatusManager.getInstance().getAppStatus() == AppStatus.STATUS_RECYVLE) {
            return;
        }
        if (Utils.isNull(Token.INSTANCE.getToken())) {
            MyApp.setAppSetting("");
        }
        Request<LzyResponse<T>, ? extends Request> request;
        if (requestType == GET) {
            request = OkGo.get(url);
        } else {
            request = OkGo.post(url);
        }
        //算出cachekey
        if (null != map && map.containsKey("pageIndex")) {
            String pageIndex = map.get("pageIndex");
            url = url + pageIndex;
        }
        request.cacheKey(url).cacheMode(cache).cacheTime(CACHE_TIME);
        Observable<LzyResponse<T>> observable = (Observable<LzyResponse<T>>) request.params(map)
                .converter(new JsonConvert<LzyResponse<T>>(typeToken))
                .adapt(new ObservableBody<LzyResponse<T>>());
        observable = observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());

        if (theLifeObj instanceof RxAppCompatActivity) {
            RxAppCompatActivity activity = (RxAppCompatActivity) theLifeObj;
            observable = observable.compose(activity.bindUntilEvent(ActivityEvent.DESTROY));
            if (showLoadingDialog) observable = observable.compose(compose(activity));
        } else if (theLifeObj instanceof RxFragment) {
            RxFragment fragment = (RxFragment) theLifeObj;
            observable = observable.compose(fragment.bindUntilEvent(FragmentEvent.DESTROY_VIEW));
            if (showLoadingDialog) observable = observable.compose(compose(fragment.getContext()));
        }
        String finalUrl = url;
        observable.subscribe(new Observer<LzyResponse<T>>() {
            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(LzyResponse<T> t) {
                try {
                    if ("200".equals(t.code)) {
                        if (callback != null) {
                        }
                        KLog.json(Convert.toJson(t));
                        callback.onSuccess(t.data);
                    } else if (t.code.startsWith("400")) {
                        HashMap<String, String> map = new HashMap<>();
                        map.put("code", t.code);
                        map.put("msg", t.msg);
                        EventBus.getDefault().post(new MyEvent(map));
                    } else {
                        if (callback != null) {
                            callback.onError(t.msg);
                        }

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    callback.onError(t.msg);
                }
            }

            @Override
            public void onError(Throwable e) {
                String message = e.getMessage();
                if (Utils.isNull(message)) return;
                if (message.contains("accessToken") || message.contains("签名") || message.contains("超时") || message.contains("试用") || message.contains("离职")) {
                    EventBus.getDefault().post(new MyEvent("Failure"));
                } else if (message.contains("充值")) {
                    EventBus.getDefault().post(new MyEvent("NoMoney"));
                }
                if (callback != null)
                    callback.onError(message);
                if (message.contains("Failed to") || message.contains("resolve host")) {
                    MyToast.show("网络不可用,请设置网络");
                } else if (message.contains("BEGIN_OBJECT") || message.contains("IllegalStateException") || message.contains("4") || message.contains("5") || message.contains("failed")) {
                    MyToast.show("服务器异常，请稍后重试");
                    KLog.e(">>>" + finalUrl);
                } else if (message.contains("but")) {
                    MyToast.show("数据格式不正确");
                }
            }

            @Override
            public void onComplete() {
            }

        });
    }

    private <T> void request(int requestType, Type typeToken, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<T> callback, CacheMode cache, boolean hideToast) {
        if (AppStatusManager.getInstance().getAppStatus() == AppStatus.STATUS_RECYVLE) {
            return;
        }
        Request<LzyResponse<T>, ? extends Request> request;
        if (requestType == GET) {
            request = OkGo.get(url);
        } else {
            request = OkGo.post(url);
        }
        //算出cachekey
        if (null != map && map.containsKey("pageIndex")) {
            String pageIndex = map.get("pageIndex");
            url = url + pageIndex;
        }
        request.cacheKey(url).cacheMode(cache).cacheTime(CACHE_TIME);
        Observable<LzyResponse<T>> observable = (Observable<LzyResponse<T>>) request.params(map)
                .converter(new JsonConvert<LzyResponse<T>>(typeToken))
                .adapt(new ObservableBody<LzyResponse<T>>());
        observable = observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());

        if (theLifeObj instanceof RxAppCompatActivity) {
            RxAppCompatActivity activity = (RxAppCompatActivity) theLifeObj;
            observable = observable.compose(activity.bindUntilEvent(ActivityEvent.DESTROY));
            if (showLoadingDialog) observable = observable.compose(compose(activity));
        } else if (theLifeObj instanceof RxFragment) {
            RxFragment fragment = (RxFragment) theLifeObj;
            observable = observable.compose(fragment.bindUntilEvent(FragmentEvent.DESTROY_VIEW));
            if (showLoadingDialog) observable = observable.compose(compose(fragment.getContext()));
        }
        observable
                .subscribe(new Observer<LzyResponse<T>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(LzyResponse<T> t) {
                        try {
                            if ("200".equals(t.code)) {

                                if (callback != null)
                                    callback.onSuccess(t.data);

                            } else if (t.code.startsWith("400")) {
                                HashMap<String, String> map = new HashMap<>();
                                map.put("code", t.code);
                                map.put("msg", t.msg);
                                EventBus.getDefault().post(new MyEvent(map));
                            } else {
                                if (callback != null)
                                    callback.onError(t.msg);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            callback.onError(e.getMessage());
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                        String message = e.getMessage();
                        if (Utils.isNull(message)) return;
                        if (message.contains("accessToken") || message.contains("签名") || message.contains("超时") || message.contains("试用") || message.contains("离职")) {
                            EventBus.getDefault().post(new MyEvent("Failure"));
                        } else if (message.contains("充值")) {
                            EventBus.getDefault().post(new MyEvent("NoMoney"));
                        }
                        if (callback != null)
                            callback.onError(message);
                        if (message.contains("Failed to") || message.contains("resolve host")) {
                            MyToast.show("网络不可用,请设置网络");
                        } else if (message.contains("BEGIN_OBJECT") || message.contains("IllegalStateException") || message.contains("4") || message.contains("5") || message.contains("failed")) {
                            MyToast.show("服务器异常，请稍后重试");
                        } else if (message.contains("but")) {
                            MyToast.show("数据格式不正确");
                        }
                    }

                    @Override
                    public void onComplete() {
                    }

                });
    }


    public void getRequestCompat(Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<String> callback) {
        requestCompat(GET, theLifeObj, url, map, showLoadingDialog, callback, CacheMode.NO_CACHE);
    }

    public void getRequestCompatHideToast(Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<String> callback) {
        requestCompatHideToast(GET, theLifeObj, url, map, showLoadingDialog, callback, CacheMode.NO_CACHE);
    }

    public void postRequestCompat(Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<String> callback) {

        requestCompat(POST, theLifeObj, url, map, showLoadingDialog, callback, CacheMode.NO_CACHE);
    }

    public static <T> ObservableTransformer<T, T> compose(final Context activity) {
        final WeakReference<Context> activityWeakReference = new WeakReference<Context>(activity);
        final LoadingDialog dialog = new LoadingDialog(activityWeakReference.get());

        return new ObservableTransformer<T, T>() {
            @Override
            public ObservableSource<T> apply(Observable<T> upstream) {
                return upstream.doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) {
                        if (!dialog.isShowing()) dialog.show();
                        KLog.e("+ dialog.show()");
                    }
                }).doOnTerminate(new Action() {
                    @Override
                    public void run() {
                        if (dialog.isShowing()) dialog.dismiss();
                    }
                });
            }
        };
    }

    /**
     * postRequest
     */
    public <T> void postRequest(Type typeToken, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<T> callback) {

        request(POST, typeToken, theLifeObj, url, map, showLoadingDialog, callback, CacheMode.NO_CACHE);
    }

    /**
     * getCacheRequest
     */
    public <T> void getCacheRequest(CacheMode cache_mode, Type typeToken, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<T> callback) {
        request(GET, typeToken, theLifeObj, url, map, showLoadingDialog, callback, cache_mode);
    }

    public <T> void getCacheRequestHideToast(CacheMode cache_mode, Type typeToken, Object theLifeObj, String url, Map<String, String> map, boolean showLoadingDialog, ObserverCallback<T> callback
    ) {
        request(GET, typeToken, theLifeObj, url, map, showLoadingDialog, callback, cache_mode, true);
    }

}